package timeslice
{
	import algorithm.DijkstraVertex;
	import algorithm.MoveRange;
	
	import away3d.animators.SkeletonAnimationSet;
	import away3d.animators.SkeletonAnimationState;
	import away3d.animators.SkeletonAnimator;
	import away3d.animators.data.Skeleton;
	import away3d.animators.transitions.CrossfadeStateTransition;
	import away3d.bounds.NullBounds;
	import away3d.entities.Mesh;
	import away3d.events.MouseEvent3D;
	import away3d.library.AssetLibrary;
	import away3d.library.assets.AssetType;
	import away3d.library.utils.AssetLibraryIterator;
	import away3d.materials.ColorMaterial;
	import away3d.primitives.PlaneGeometry;
	import away3d.primitives.WireframePlane;
	
	import data.MetaMap;
	
	import flash.events.KeyboardEvent;
	import flash.ui.Keyboard;
	
	import globals.$root;
	import globals.$stage;
	
	import slices.TimeSlice;
	
	import test.DebugView;
	
	public class DisplayMap extends TimeSlice
	{
		private var _view:DebugView;
		
		private var hero:Mesh;
		private var _bear:Mesh;
		private var _city:Mesh;
		private var _grid:Mesh;
		private var _cursor:Mesh;
		private var _gridWidth:int = 50;
		private var _grids:WireframePlane;
		private var _metaMap:MetaMap;

		public function DisplayMap()
		{
			super();
			_view = new DebugView();
			$root.stage.addChild(_view);
		}
		
		override public function onStart():void {
			hero = Mesh(AssetLibrary.getAsset("ONKBA-Corps-lnew", "hero"));
//			hero.scale(8);
//			hero.z = 1000;
//			hero.rotationY = -45;
//			_human.x = 100;
			hero.z = 100;
			hero.y = 50;
			_view.scene.addChild(hero);

			skeleton = Skeleton(AssetLibrary.getAsset("Bone001", "hero"));
			breatheState = SkeletonAnimationState(AssetLibrary.getAsset("Breathe", "hero"));
			walkState = SkeletonAnimationState(AssetLibrary.getAsset("Walk", "hero"));
			runState = SkeletonAnimationState(AssetLibrary.getAsset("Run", "hero"));
			
			// Create an animation set object and add our state objects
			animationSet = new SkeletonAnimationSet(3);
			animationSet.addState(breatheState.name, breatheState);
			animationSet.addState(walkState.name, walkState);
			animationSet.addState(runState.name, runState);
			
			//couple our animation set with our skeleton and wrap in an animator object and apply to our mesh object
			animator = new SkeletonAnimator(animationSet, skeleton);
			animator.updateRootPosition = true;
//			animator.updateRootPosition = false;
			hero.animator = animator;
			
			//create our crossfade transition object
			crossfadeTransition = new CrossfadeStateTransition(XFADE_TIME);
			
			_bear = Mesh(AssetLibrary.getAsset("PolarBear", "bear"));
			_bear.material = new ColorMaterial(0xFFFFFF);
			var ast:SkeletonAnimationSet = new SkeletonAnimationSet(3);
			var state:SkeletonAnimationState;
			var skn:Skeleton = AssetLibrary.getAsset("ZeroJoint.1", "bear") as Skeleton;
			state = AssetLibrary.getAsset("Breathe", "bear") as SkeletonAnimationState;
			ast.addState(state.name, state);
			state = AssetLibrary.getAsset("Walk", "bear") as SkeletonAnimationState;
			ast.addState(state.name, state);
			state = AssetLibrary.getAsset("Run", "bear") as SkeletonAnimationState;
			ast.addState(state.name, state);
			var atr:SkeletonAnimator = new SkeletonAnimator(ast, skn);
			_bear.animator = atr;
			_bear.scale(0.3);
			_view.scene.addChild(_bear);
			
			var ite:AssetLibraryIterator = AssetLibrary.createIterator(AssetType.MESH, "map");
			var mesh:Mesh = Mesh(ite.next());
			while (mesh != null) {
				_view.scene.addChild(mesh);
				mesh = Mesh(ite.next());
			}
			
			mesh = Mesh(AssetLibrary.getAsset("Plane001", "map"));
			mesh.mouseEnabled = true;
			mesh.addEventListener(MouseEvent3D.MOUSE_DOWN, onMouseDownOnMap);
			
			_grids = new WireframePlane(2000, 2000, 2000/_gridWidth, 2000/_gridWidth, 0xFFFFFF, 2, "xz");
			_view.scene.addChild(_grids);
			
			_cursor = new Mesh(new PlaneGeometry(_gridWidth, _gridWidth), new ColorMaterial(0xFF0000, 0.6));
			_cursor.y = 0.1;
			_view.scene.addChild(_cursor);
			
			_metaMap = new MetaMap();
			
			goToPauseState();
			
			initListeners();
		}
		
		private function onMouseDownOnMap(e:MouseEvent3D):void {
			trace(e.localPosition);
			setCursorAt(e.localPosition.x, e.localPosition.z);
		}
		
		private function setCursorAt(x:Number, z:Number):void {
			var gx:int = Math.floor(x / _gridWidth);
			var gz:int = Math.floor(z / _gridWidth);
			trace("set cursor at x:" + gx + " z:" + gz);
			_cursor.x = gx * _gridWidth + _gridWidth/2;
			_cursor.z = gz * _gridWidth + _gridWidth/2;
		}
		
		//animation variables
		private var skeleton:Skeleton;
		private var animationSet:SkeletonAnimationSet;
		private var animator:SkeletonAnimator;
		private var breatheState:SkeletonAnimationState;
		private var walkState:SkeletonAnimationState;
		private var runState:SkeletonAnimationState;
		private var crossfadeTransition:CrossfadeStateTransition;
		private var isRunning:Boolean;
		private var isMoving:Boolean;
		private var movementDirection:Number;
		private var currentAnim:String;
		private var currentRotationInc:Number = 0;
		
		//animation constants
		private const ANIM_BREATHE:String = "Breathe";
		private const ANIM_WALK:String = "Walk";
		private const ANIM_RUN:String = "Run";
		private const XFADE_TIME:Number = 0.5;
		private const ROTATION_SPEED:Number = 3;
		private const RUN_SPEED:Number = 2;
		private const WALK_SPEED:Number = 1;
		private const BREATHE_SPEED:Number = 1;				
		
		/**
		 * Initialise the listeners
		 */
		private function initListeners():void
		{
			// Listen for key presses
			$root.stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
			$root.stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
		}
		
		/**
		 * Key down listener for animation
		 */
		private function onKeyDown(event:KeyboardEvent):void
		{
			switch (event.keyCode) {
				case Keyboard.SHIFT:
					isRunning = true;
					if (isMoving)
						updateMovement(movementDirection);
					break;
				case Keyboard.UP:
				case Keyboard.W:
					updateMovement(movementDirection = 1);
					break;
				case Keyboard.DOWN:
				case Keyboard.S:
					updateMovement(movementDirection = -1);
					break;
				case Keyboard.LEFT:
				case Keyboard.A:
					currentRotationInc = -ROTATION_SPEED;
					break;
				case Keyboard.RIGHT:
				case Keyboard.D:
					currentRotationInc = ROTATION_SPEED;
					break;
			}
		}
		
		private function onKeyUp(event:KeyboardEvent):void
		{
			switch (event.keyCode) {
				case Keyboard.SHIFT:
					isRunning = false;
					if (isMoving)
						updateMovement(movementDirection);
					break;
				case Keyboard.UP:
				case Keyboard.W:
				case Keyboard.DOWN:
				case Keyboard.S:
					goToPauseState();
					break;
				case Keyboard.LEFT:
				case Keyboard.A:
				case Keyboard.RIGHT:
				case Keyboard.D:
					currentRotationInc = 0;
					break;
			}
		}

		private function goToPauseState():void
		{
			isMoving = false;
			
			//update animator speed
			animator.playbackSpeed = BREATHE_SPEED;
			_bear.animator.playbackSpeed = BREATHE_SPEED;
			
			//update animator sequence
			if (currentAnim == ANIM_BREATHE)
				return;
			
			currentAnim = ANIM_BREATHE;
			
			animator.play(currentAnim, crossfadeTransition);
			_bear.animator.play(currentAnim, crossfadeTransition);
		}
		
		private function updateMovement(dir:Number):void
		{
			isMoving = true;
			
			//update animator speed
			animator.playbackSpeed = dir * (isRunning ? RUN_SPEED : WALK_SPEED);
			_bear.animator.playbackSpeed = dir * (isRunning ? RUN_SPEED : WALK_SPEED);
			
			//update animator sequence
			var anim:String = isRunning ? ANIM_RUN : ANIM_WALK;
			if (currentAnim == anim)
				return;
			
			currentAnim = anim;
			
			animator.play(currentAnim, crossfadeTransition);
			_bear.animator.play(currentAnim, crossfadeTransition);
		}
		
		override public function onUpdate():void {
			if (hero) hero.rotationY += currentRotationInc;
		}

	}
}